Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | import { notFound, redirect } from 'next/navigation' import { getPlayerAccess, isParentOf } from '@/lib/classroom' import { getActiveSessionPlan, getPracticeStudent } from '@/lib/curriculum/server' import type { ActiveSessionInfo } from '@/hooks/useClassroom' import { getUserId } from '@/lib/viewer' import { ObservationClient } from './ObservationClient' import { StudentNotPresentPage } from './StudentNotPresentPage' export const dynamic = 'force-dynamic' interface ObservationPageProps { params: Promise<{ studentId: string }> } export default async function PracticeObservationPage({ params }: ObservationPageProps) { const { studentId } = await params const [observerId, player, activeSession] = await Promise.all([ getUserId(), getPracticeStudent(studentId), getActiveSessionPlan(studentId), ]) if (!player) { notFound() } const [access, isParent] = await Promise.all([ getPlayerAccess(observerId, studentId), isParentOf(observerId, studentId), ]) // Check if user can observe (parent or teacher-present) const canObserve = access.isParent || access.isPresent if (!canObserve) { // If they're a teacher but student isn't present, show helpful message if (access.isTeacher && access.classroomId) { return ( <StudentNotPresentPage studentName={player.name} studentEmoji={player.emoji} studentId={studentId} classroomId={access.classroomId} /> ) } // Otherwise, they have no relationship to this student notFound() } // If session is completed, show the observation page with a banner linking to the report if (activeSession?.completedAt) { return ( <ObservationClient session={{ sessionId: activeSession.id, playerId: activeSession.playerId, startedAt: activeSession.startedAt!.toISOString(), currentPartIndex: activeSession.currentPartIndex, currentSlotIndex: activeSession.currentSlotIndex, totalParts: activeSession.parts.length, totalProblems: activeSession.parts.reduce((sum, part) => sum + part.slots.length, 0), completedProblems: activeSession.parts.reduce((sum, part) => sum + part.slots.length, 0), }} observerId={observerId} student={{ name: player.name, emoji: player.emoji, color: player.color, }} studentId={studentId} isParent={isParent} sessionReportUrl={`/practice/${studentId}/session/${activeSession.id}`} sessionEnded /> ) } // If no active session or session hasn't started, go to dashboard if (!activeSession || !activeSession.startedAt) { redirect(`/practice/${studentId}/dashboard`) } const totalProblems = activeSession.parts.reduce((sum, part) => sum + part.slots.length, 0) let completedProblems = 0 for (let i = 0; i < activeSession.currentPartIndex; i++) { completedProblems += activeSession.parts[i]?.slots.length ?? 0 } completedProblems += activeSession.currentSlotIndex const session: ActiveSessionInfo = { sessionId: activeSession.id, playerId: activeSession.playerId, startedAt: activeSession.startedAt!.toISOString(), currentPartIndex: activeSession.currentPartIndex, currentSlotIndex: activeSession.currentSlotIndex, totalParts: activeSession.parts.length, totalProblems, completedProblems, } return ( <ObservationClient session={session} observerId={observerId} student={{ name: player.name, emoji: player.emoji, color: player.color, }} studentId={studentId} isParent={isParent} /> ) } |